#include "parser.h"
#include <iostream>
parser::parser()
{
    this->lexer = nullptr;
}

parser::parser(LEX* lex)
{
    this->lexer = lex;
}

unique_ptr<ExprAST> parser::parseExpr()
{
    unique_ptr<ExprAST>ret = this->parseLOrExp();
    this->lexer->match(TOK::SEMICOLON);
    return ret;
}

unique_ptr<ExprAST> parser::parseExp()
{
    return this->parseLOrExp();
}

unique_ptr<ExprAST> parser::parsePrimaryExp()
{
    if (this->lexer->next_token() == TOK::LPAREN)
    {
        this->lexer->match(TOK::LPAREN);
        unique_ptr<ExprAST>ret = this->parseExp();
        this->lexer->match(TOK::RPAREN);
        return ret;
    }
    if (this->lexer->next_token() == TOK::NUMBER)
        return this->parseNumber();
    std::cerr << "unexpected token." << std::endl;
    exit(-1);
}

unique_ptr<ExprAST> parser::parseNumber()
{
    unique_ptr<NumberAST>ret(new NumberAST());
    ret->content = atoi(this->lexer->get_buffer().c_str());
    this->lexer->match(TOK::NUMBER);
    return ret;
}

unique_ptr<ExprAST> parser::parseUnaryExp()
{
    unique_ptr<UnaryAST>ret;
    switch (this->lexer->next_token())
    {
    case TOK::PLUS:
        this->lexer->match(TOK::PLUS);
        ret.reset(new UnaryAST);
        ret->op = UnaryAST::POS;
        ret->content = this->parseUnaryExp();
        return ret;
    case TOK::MINUS:
        this->lexer->match(TOK::MINUS);
        ret.reset(new UnaryAST);
        ret->op = UnaryAST::NEG;
        ret->content = this->parseUnaryExp();
        return ret;
    case TOK::NOT:
        this->lexer->match(TOK::NOT);
        ret.reset(new UnaryAST);
        ret->op = UnaryAST::NOT;
        ret->content = this->parseUnaryExp();
        return ret;
    default:
        return this->parsePrimaryExp();
    }
}

unique_ptr<ExprAST> parser::parseMulExp()
{
    unique_ptr<ExprAST>l = this->parseUnaryExp();
    while (this->lexer->next_token() == TOK::MUL || this->lexer->next_token() == TOK::DIV || this->lexer->next_token() == TOK::MOD)
    {
        unique_ptr<MulAST>t(new MulAST);
        switch (this->lexer->next_token())
        {
        case TOK::MUL:
            t->op = MulAST::MUL;
            break;
        case TOK::MOD:
            t->op = MulAST::MOD;
            break;
        case TOK::DIV:
            t->op = MulAST::DIV;
            break;
        default:
            break;
        }
        this->lexer->match(this->lexer->next_token());
        t->exp1 = std::move(l);
        t->exp2= this->parseUnaryExp();
        l = std::move(t);
        t = nullptr;
    }
    return l;
}

unique_ptr<ExprAST> parser::parseAddExp()
{
    unique_ptr<ExprAST>l = this->parseMulExp();
    while (this->lexer->next_token() == TOK::PLUS || this->lexer->next_token() == TOK::MINUS)
    {
        unique_ptr<AddAST>t(new AddAST);
        switch (this->lexer->next_token())
        {
        case TOK::PLUS:
            t->op = AddAST::ADD;
            break;
        case TOK::MINUS:
            t->op = AddAST::SUB;
            break;
        default:
            break;
        }
        this->lexer->match(this->lexer->next_token());
        t->exp1 = std::move(l);
        t->exp2 = this->parseMulExp();
        l = std::move(t);
        t = nullptr;
    }
    return l;
}

unique_ptr<ExprAST> parser::parseRelExp()
{
    unique_ptr<ExprAST>l = this->parseAddExp();
    while (this->lexer->next_token() == TOK::GT || this->lexer->next_token() == TOK::GE || this->lexer->next_token() == TOK::LT || this->lexer->next_token() == TOK::LE)
    {
        unique_ptr<RelAST>t(new RelAST);
        switch (this->lexer->next_token())
        {
        case TOK::GT:
            t->op = RelAST::GT;
            break;
        case TOK::GE:
            t->op = RelAST::GE;
            break;
        case TOK::LT:
            t->op = RelAST::LT;
            break;
        case TOK::LE:
            t->op = RelAST::LE;
            break;
        default:
            break;
        }
        this->lexer->match(this->lexer->next_token());
        t->exp1 = std::move(l);
        t->exp2 = this->parseAddExp();
        l = std::move(t);
        t = nullptr;
    }
    return l;
}

unique_ptr<ExprAST> parser::parseEqExp()
{
    unique_ptr<ExprAST>l = this->parseRelExp();
    while (this->lexer->next_token() == TOK::EQ || this->lexer->next_token() == TOK::NE)
    {
        unique_ptr<EqAST>t(new EqAST);
        switch (this->lexer->next_token())
        {
        case TOK::EQ:
            t->op = EqAST::EQ;
            break;
        case TOK::NE:
            t->op = EqAST::NE;
            break;
        default:
            break;
        }
        this->lexer->match(this->lexer->next_token());
        t->exp1 = std::move(l);
        t->exp2 = this->parseRelExp();
        l = std::move(t);
        t = nullptr;
    }
    return l;
}

unique_ptr<ExprAST> parser::parseLAndExp()
{
    unique_ptr<ExprAST>l = this->parseEqExp();
    while (this->lexer->next_token() == TOK::LAND)
    {
        unique_ptr<LAndAST>t(new LAndAST);
        t->op = true;
        this->lexer->match(TOK::LAND);
        t->exp1 = std::move(l);
        t->exp2 = this->parseEqExp();
        l = std::move(t);
        t = nullptr;
    }
    return l;
}

unique_ptr<ExprAST> parser::parseLOrExp()
{
    unique_ptr<ExprAST>l = this->parseLAndExp();
    while (this->lexer->next_token() == TOK::LOR)
    {
        unique_ptr<LOrAST>t(new LOrAST);
        t->op = true;
        this->lexer->match(TOK::LOR);
        t->exp1 = std::move(l);
        t->exp2 = this->parseLAndExp();
        l = std::move(t);
        t = nullptr;
    }
    return l;
}
